/*
 * @Description: 
 * @Version: 1.0
 * @Autor: jiajun wu
 * @Date: 2021-07-23 21:37:20
 * @LastEditors: jiajun wu
 * @LastEditTime: 2021-07-23 23:31:59
 */
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')

const statusConfig = {
  IDLE: 0,
  DRAG_START: 1,
  DRAGGING: 2,
  MOVE_START: 3,
  MOVING: 4
}

const canvasInfo = {
  status: statusConfig.IDLE,
  dragTarget: undefined,
  lastEvtPos: { x: undefined, y: undefined },
  offsetEvtPos: { x: undefined, y: undefined },
  offsetMouseEvtPos: { x: undefined, y: undefined },
  offset: { x: 0, y: 0 }, // 缩放
  scale: 1,
  scaleStep: 0.1,
  maxScale: 2,
  minScale: 0.5
}

const cirlces = []

const drawCircle = (ctx, cx, cy, r) => {
  ctx.save()
  ctx.beginPath()

  ctx.strokeStyle = "blue"
  ctx.arc(cx, cy, r, 0, Math.PI * 2, false)
  ctx.stroke()
  ctx.closePath()
  ctx.restore()
}

drawCircle(ctx, 100, 100, 20)
cirlces.push({
  x: 100,
  y: 100,
  r: 20
})
drawCircle(ctx, 200, 200, 10)
cirlces.push({
  x: 200,
  y: 200,
  r: 10
})

const getCanvasPosition = (e, offset = { x: 0, y: 0 }, scale = 1) => {
  return {
    x: (e.offsetX - offset.x) / scale,
    y: (e.offsetY - offset.y) / scale,
  }
}

const getMousePosition = e => {
  return {
    x: e.offsetX,
    y: e.offsetY
  }
}

const getDistance = (p1, p2) => {
  return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2)
}

const ifInCircle = (pos) => {
  for (let i = 0; i < cirlces.length; i++) {
    if (getDistance(cirlces[i], pos) < cirlces[i].r) {
      return cirlces[i]
    }
  }
  return false
}

canvas.oncontextmenu = function () {
  return false
}

canvas.addEventListener('mousedown', e => {
  const canvasPosition = getCanvasPosition(e, canvasInfo.offset, canvasInfo.scale)
  const circleRef = ifInCircle(canvasPosition)
  if (e.button === 0) {
    if (circleRef) {
      canvasInfo.dragTarget = circleRef
      canvasInfo.status = statusConfig.DRAG_START
      canvasInfo.lastEvtPos = canvasPosition
      canvasInfo.offsetEvtPos = canvasPosition
    }
  } else if (e.button === 2) {
    if (!circleRef) {
      canvasInfo.status = statusConfig.MOVE_START
      canvasInfo.offsetMouseEvtPos = getMousePosition(e)
    }
  }
})

canvas.addEventListener('mousemove', e => {
  const canvasPosition = getCanvasPosition(e, canvasInfo.offset, canvasInfo.scale)

  if (ifInCircle(canvasPosition)) {
    canvas.style.cursor = 'all-scroll'
  } else {
    canvas.style.cursor = 'default'
  }

  if (canvasInfo.status === statusConfig.DRAG_START && getDistance(canvasPosition, canvasInfo.lastEvtPos) > 5) {
    canvasInfo.status = statusConfig.DRAGGING
    canvasInfo.offsetEvtPos = canvasPosition

  } else if (canvasInfo.status === statusConfig.DRAGGING) {
    const { dragTarget } = canvasInfo
    dragTarget.x += canvasPosition.x - canvasInfo.offsetEvtPos.x
    dragTarget.y += canvasPosition.y - canvasInfo.offsetEvtPos.y

    ctx.clearRect(0, 0, canvas.width, canvas.height)
    cirlces.forEach(c => drawCircle(ctx, c.x, c.y, c.r))

    canvasInfo.offsetEvtPos = canvasPosition
  } else if (canvasInfo.status === statusConfig.MOVE_START && getDistance(canvasPosition, canvasInfo.lastEvtPos) > 5) {
    canvasInfo.status = statusConfig.MOVING
    canvasInfo.offsetMouseEvtPos = getMousePosition(e)
  } else if (canvasInfo.status === statusConfig.MOVING) { // 移动
    const mousePosition = getMousePosition(e)
    console.log("moving");
    canvasInfo.offset.x += mousePosition.x - canvasInfo.offsetMouseEvtPos.x
    canvasInfo.offset.y += mousePosition.y - canvasInfo.offsetMouseEvtPos.y

    ctx.setTransform(canvasInfo.scale, 0, 0, canvasInfo.scale, canvasInfo.offset.x, canvasInfo.offset.y)
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    cirlces.forEach(c => drawCircle(ctx, c.x, c.y, c.r))
    canvasInfo.offsetMouseEvtPos = mousePosition
  }
})

canvas.addEventListener('mouseup', e => {
  if (canvasInfo.status === statusConfig.DRAGGING || canvasInfo.status === statusConfig.MOVING) {
    canvasInfo.status = statusConfig.IDLE
  }
})

canvas.addEventListener('wheel', e => {
  e.preventDefault()
  const canvasPosition = getCanvasPosition(e, canvasInfo.offset)
  const { scaleStep, maxScale, minScale } = canvasInfo
  const deltaX = canvasPosition.x / canvasInfo.scale * scaleStep
  const deltaY = canvasPosition.y / canvasInfo.scale * scaleStep

  if (e.wheelDelta > 0 && canvasInfo.scale < maxScale) {
    canvasInfo.offset.x -= deltaX
    canvasInfo.offset.y -= deltaY
    canvasInfo.scale += scaleStep
  } else if (e.wheelDelta <= 0 && canvasInfo.scale > minScale) {
    canvasInfo.offset.x += deltaX
    canvasInfo.offset.y += deltaY
    canvasInfo.scale -= scaleStep
  }
  ctx.setTransform(canvasInfo.scale, 0, 0, canvasInfo.scale, canvasInfo.offset.x, canvasInfo.offset.y)
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  cirlces.forEach(c => drawCircle(ctx, c.x, c.y, c.r))

})